From 93d469145452d334e108da2494545898d20811f8 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 8 Sep 2025 14:14:15 +0200 Subject: [PATCH] [PATCH] ws: get a new mask for each new outgoing frame Reported-by: Calvin Ruocco Closes #18496 Backported-by: Samuel Henrique Backported-by: Alex Changes: * Refresh patch context for lib/ws.c * Adapt return value to current function return type Backported by: Samuel Henrique Changes: * Apply the per-frame mask generation in ws_packethead() (bookworm 7.88.1) rather than upstream's ws_enc_add_frame() (and trixie's ws_enc_write_head()), since the bookworm code path that builds the outgoing frame header is structurally different. On Curl_rand() failure return 0 -- ws_packethead() already uses 0 as the soft-error sentinel for buffer-too-small. * Preserve the DEBUGBUILD CURL_WS_FORCE_ZERO_MASK escape hatch alongside the new per-frame mask generation, matching upstream. * Remove the corresponding one-time mask generation in Curl_ws_accept(), and initialise `result` to CURLE_OK at declaration since it is no longer unconditionally assigned by the removed Curl_rand() call. Gbp-Pq: Name CVE-2025-10148.patch --- lib/ws.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/lib/ws.c b/lib/ws.c index 0fc5e56a..992357ca 100644 --- a/lib/ws.c +++ b/lib/ws.c @@ -127,7 +127,7 @@ CURLcode Curl_ws_accept(struct Curl_easy *data, struct connectdata *conn = data->conn; struct websocket *wsp = &data->req.p.http->ws; struct ws_conn *wsc = &conn->proto.ws; - CURLcode result; + CURLcode result = CURLE_OK; /* Verify the Sec-WebSocket-Accept response. @@ -148,13 +148,7 @@ CURLcode Curl_ws_accept(struct Curl_easy *data, subprotocol not requested by the client), the client MUST Fail the WebSocket Connection. */ - /* 4 bytes random */ - result = Curl_rand(data, (unsigned char *)&ws->ws.mask, sizeof(ws->ws.mask)); - if(result) - return result; - - infof(data, "Received 101, switch to WebSocket; mask %02x%02x%02x%02x", - ws->ws.mask[0], ws->ws.mask[1], ws->ws.mask[2], ws->ws.mask[3]); + infof(data, "Received 101, switch to WebSocket"); Curl_dyn_init(&wsc->early, data->set.buffer_size); if(nread) { result = Curl_dyn_addn(&wsc->early, mem, nread); @@ -628,6 +622,20 @@ static size_t ws_packethead(struct Curl_easy *data, firstbyte); infof(data, "WS: send payload len %u", (int)len); + /* 4 bytes random */ + { + CURLcode result = Curl_rand(data, (unsigned char *)&ws->ws.mask, + sizeof(ws->ws.mask)); + if(result) + return 0; + } + +#ifdef DEBUGBUILD + if(getenv("CURL_WS_FORCE_ZERO_MASK")) + /* force the bit mask to 0x00000000, effectively disabling masking */ + memset(&ws->ws.mask, 0, sizeof(ws->ws.mask)); +#endif + /* 4 bytes mask */ memcpy(&out[outi], &ws->ws.mask, 4); -- 2.30.2